package com.xiaomo.gitee.datamanager.service.image.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xiaomo.gitee.datamanager.aspect.log.anno.SysLog;
import com.xiaomo.gitee.datamanager.cache.RedisCacheManager;
import com.xiaomo.gitee.datamanager.common.result.ImageWrapper;
import com.xiaomo.gitee.datamanager.mapper.*;
import com.xiaomo.gitee.datamanager.entity.ImageTag;
import com.xiaomo.gitee.datamanager.entity.Imagedes;
import com.xiaomo.gitee.datamanager.entity.Images;
import com.xiaomo.gitee.datamanager.service.category.ClassInfoService;
import com.xiaomo.gitee.datamanager.service.image.ImageService;
import com.xiaomo.gitee.datamanager.service.category.impl.ClassInfoServiceImpl;
import com.xiaomo.gitee.datamanager.util.ImagesSequenceUtils;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.Executor;

@Service
@RequiredArgsConstructor
public class ImageServiceImpl implements ImageService {

    @Value("${upload.dir}")
    private String uploadDirectory;

    private final ImagesMapper imagesMapper;
    private final ImagedesMapper imagedesMapper;
    private final ImageTagMapper imageTagMapper;
    private final TagsMapper tagsMapper;
    private final ImagesSequenceUtils imagesSequenceUtils;
    private final Executor executor;

    private final ClassInfoService classInfoServiceImpl;

    @Override
    @SysLog("上传图片")
    public void uploadImage(Long pCategoryId, Long subCategoryId, String description, MultipartFile[] imageFiles) {
        String sDir = uploadDirectory + File.separator + "small";
        String bDir = uploadDirectory + File.separator + "original";

        try {
            List<Images> images = new ArrayList<>();
            List<Imagedes> imagedes = new ArrayList<>();
            for (MultipartFile imageFile : imageFiles) {
                String randomUUID = UUID.randomUUID().toString();
                String oName = imageFile.getOriginalFilename();
                String name = oName.substring(0, oName.length() - 4);
                File targetFile = new File(bDir, randomUUID + ".jpg");
                imageFile.transferTo(targetFile);
                File outputFile = new File(sDir, randomUUID + ".jpg");
                Thumbnails.of(targetFile)
                        .size(211, 118)
                        .toFile(outputFile);
                images.add(new Images(randomUUID, name, subCategoryId));
                imagedes.add(new Imagedes(randomUUID, description));
            }
            imagesMapper.insertBatch(images);
/*            executor.execute(() -> {
                    redisUtils.lPushAll("category:" + subCategoryId,images);
            });*/
            imagedesMapper.insertBatch(imagedes);
            imagesSequenceUtils.loadImagesSequence();
        } catch (IOException e) {
            e.printStackTrace();
        }

        MDC.put("图片数量", String.valueOf(imageFiles.length));
        MDC.put("数据集Id", subCategoryId.toString());
        MDC.put("大类别Id", pCategoryId.toString());

    }

    @SysLog("删除图片")
    @Override
    public void deleteImage(String id) {

        Images image = imagesMapper.selectOneById(id);

/*        executor.execute(() -> {
            redisUtils.lRemove("category:" + image.getClassification(),0,image);
        });*/

        String s = File.separator;
        String sDir = uploadDirectory + s + "small";
        String bDir = uploadDirectory + s + "original";
        imageTagMapper.deleteByImageId(id);
        try {
            Files.deleteIfExists(Paths.get(sDir + s + id + ".jpg"));
            Files.deleteIfExists(Paths.get(bDir + s + id + ".jpg"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        imagesMapper.deleteById(id);
        imagesSequenceUtils.loadImagesSequence();

        MDC.put("图片Id", id);

    }


    public ResponseEntity<byte[]> getOriginalImage(String id) {
        String s = File.separator;
        try {
            File file = new File(uploadDirectory + s + "original" + s + id + ".jpg");
            if (!file.exists())
                return null;
            FileInputStream stream = new FileInputStream(file);
            byte[] data = stream.readAllBytes();
            stream.close();
            return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public ResponseEntity<byte[]> getSmallImage(String id) {
        String s = File.separator;
        try {
            File file = new File(uploadDirectory + s + "small" + s + id + ".jpg");
            if (!file.exists())
                return null;
            FileInputStream stream = new FileInputStream(file);
            byte[] data = stream.readAllBytes();
            stream.close();
            return ResponseEntity.ok().contentType(MediaType.IMAGE_JPEG).body(data);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * @param page     页数
     * @param category 子类别id
     * @return 图片json数据
     */
    @Override
    public Map<String, Object> getClassifiedImagesService(Long category, int page, int amountPerPage) {
        List<Images> list = imagesMapper.selectImagesWithRowNumber(category, (long) (page - 1) * amountPerPage, amountPerPage, "name");
        QueryWrapper<Images> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("classification", category);
        long size = imagesMapper.selectCount(queryWrapper);
        Map<String, Object> resultMap = new HashMap<>();
        List<ImageWrapper> imageList = new ArrayList<>();
        for (Images images : list) {
            imageList.add(new ImageWrapper(images.getName(), images.getId(), classInfoServiceImpl.getChildClassById(category).getName(), images.getSequenceNumber()));
        }

        resultMap.put("imagesInfo", imageList);
        resultMap.put("imageAmount", size);
        return resultMap;

//        return redisCacheManager.getClassifiedImages(category,page,amountPerPage);
    }

    @Override
    public Map<String, Object> searchImagesService(String info, int page, int amountPerPage) {
        var temp = new Object() {
            List<Images> imagesList = new ArrayList<>();
        };
        tagsMapper.searchTagsByName(info, "content").forEach(tag -> {
            temp.imagesList.addAll(imageTagMapper.selectAllByTagId(tag.getId()).stream().map(imageTag -> imagesMapper.selectOneById(imageTag.getImageId())).toList());
        });
        List<Images> imagesList = temp.imagesList;
        imagesList.addAll(imagesMapper.searchImagesByName(info, "name"));
        int size = imagesList.size();
        int currentIndex = (page - 1) * amountPerPage;
        imagesList = imagesList.subList(currentIndex, Math.min(currentIndex + amountPerPage, size));

        List<ImageWrapper> resultList = new ArrayList<>();
        for (Images images : imagesList) {
            resultList.add(new ImageWrapper(images.getName(), images.getId(), classInfoServiceImpl.getChildClassById(images.getClassification()).getName(), imagesSequenceUtils.sequenceMap.get(images.getId())));
        }
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("imagesInfo", resultList);
        resultMap.put("imageAmount", size);
        return resultMap;
    }

    @Override
    public Map<String, Object> filterImages(List<Long> tagsId, int page, int amountPerPage) {
        QueryWrapper<ImageTag> imageTagQueryWrapper = new QueryWrapper<>();
        imageTagQueryWrapper.in("tag_id", tagsId);
        List<String> imagesId = imageTagMapper.selectList(imageTagQueryWrapper).stream().map(ImageTag::getImageId).toList().stream().distinct().toList();
        int size = imagesId.size();
        if (size == 0) {
            Map<String, Object> map = new HashMap<>();
            map.put("imagesInfo", null);
            map.put("imageAmount", size);
            return map;
        }
        QueryWrapper<Images> imagesQueryWrapper = new QueryWrapper<>();
        imagesQueryWrapper.last("LIMIT " + (page - 1) * amountPerPage + ", " + amountPerPage);
        imagesQueryWrapper.orderBy(true, true, "id");
        imagesQueryWrapper.in("id", imagesId);
        List<Images> images = imagesMapper.selectList(imagesQueryWrapper);


        List<ImageWrapper> result;
        result = images.stream().map(images1 -> new ImageWrapper(
                images1.getName(),
                images1.getId(),
                classInfoServiceImpl.getChildClassById(images1.getClassification()).getName(),
                imagesSequenceUtils.sequenceMap.get(images1.getId())
        )).toList();
        Map<String, Object> map = new HashMap<>();
        map.put("imagesInfo", result);

        map.put("imageAmount", size);
        return map;
    }

    @Override
    public String getDescription(String id) {
        return imagedesMapper.selectById(id).getDescription();
    }
}
